package com.yuanxin.yuanxinwebview;

import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.DownloadManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.webkit.ConsoleMessage;
import android.webkit.DownloadListener;
import android.webkit.GeolocationPermissions;
import android.webkit.HttpAuthHandler;
import android.webkit.JavascriptInterface;
import android.webkit.JsResult;
import android.webkit.MimeTypeMap;
import android.webkit.SslErrorHandler;
import android.webkit.URLUtil;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.react.uimanager.events.RCTEventEmitter;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Nullable;


/**
 * Created by lemon on 16/8/9.
 */
public class YuanXinWebViewManager extends SimpleViewManager<WebView> {
    private static final String REACT_CLASS = "YuanXinWebView";
    private static final String TAG = YuanXinWebViewManager.class.getName();
    private static final String HTML_ENCODING = "UTF-8";
    private static final String HTML_MIME_TYPE = "text/html; charset=utf-8";

    private static final String HTTP_METHOD_POST = "POST";

    public static final int COMMAND_GO_BACK = 1;
    public static final int COMMAND_GO_FORWARD = 2;
    public static final int COMMAND_RELOAD = 3;
    public static final int COMMAND_STOP_LOADING = 4;
    private static final int COMMAND_SEND_TO_BRIDGE = 5;
    private static final int COMMAND_SEND_DATA_BRIDGE = 6;
    private static final int COMMAND_EVALUATE_SCRIPT = 7;

    private static String userName = null;
    private static String password = null;

    private WebView contentWebView;
    List<WebView> webViewList = new ArrayList<>();

    // Use `webView.loadUrl("about:blank")` to reliably reset the view
    // state and release page resources (including any running JavaScript).
    private static final String BLANK_URL = "about:blank";

    private WebViewConfig mWebViewConfig;

    //是否启用资源缓存  true 启用 false 不启用
    boolean assetsCacheEnable = false;
    private String  downloadUrl;
    private class ReactWebViewClient extends WebViewClient {

        private boolean mLastLoadFailed = false;

        @Override
        public void onPageFinished(WebView webView, String url) {
            super.onPageFinished(webView, url);
            Log.e(TAG, "url="+url);
            ReactWebView reactWebView = (ReactWebView) webView;
            reactWebView.callInjectedJavaScript();
            if (!mLastLoadFailed) {
                emitFinishEvent(webView, url);
            }
//            webView.loadUrl("javascript:WebViewBridge.onGetWebContentHeight(document.body.clientHeight)");
        }


        @Override
        public void onPageStarted(WebView webView, String url, Bitmap favicon) {
            super.onPageStarted(webView, url, favicon);
            mLastLoadFailed = false;

            ReactWebView reactWebView = (ReactWebView) webView;
            reactWebView.callInjectedJavaScript();

            dispatchEvent(
                    webView,
                    new TopLoadingStartEvent(
                            webView.getId(),
                            createWebViewEvent(webView, url)));

        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if(url.startsWith("https") || url.startsWith("http")){
                view.loadUrl(url,headerMap);
            }else{
                try {
                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                    view.getContext().startActivity(intent);
                } catch (ActivityNotFoundException e) {
                    e.printStackTrace();
                }
            }
            return true;
        }

        @Override
        public void onReceivedError(
                WebView webView,
                int errorCode,
                String description,
                String failingUrl) {
            super.onReceivedError(webView, errorCode, description, failingUrl);
            //当确认该次失败为下载链接时候，不走下面错误页面展示
            if(!TextUtils.isEmpty(downloadUrl) && downloadUrl.equals(failingUrl)){
                return;
            }
            mLastLoadFailed = true;

            // In case of an error JS side expect to get a finish event first, and then get an error event
            // Android WebView does it in the opposite way, so we need to simulate that behavior
            emitFinishEvent(webView, failingUrl);

            WritableMap eventData = createWebViewEvent(webView, failingUrl);
            eventData.putDouble("code", errorCode);
            eventData.putString("description", description);

            dispatchEvent(
                    webView,
                    new TopLoadingErrorEvent(webView.getId(), eventData));

        }

        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
//            super.onReceivedSslError(view, handler, error);
            handler.proceed();
        }

        @Override
        public void doUpdateVisitedHistory(WebView webView, String url, boolean isReload) {
            super.doUpdateVisitedHistory(webView, url, isReload);

            dispatchEvent(
                    webView,
                    new TopLoadingStartEvent(
                            webView.getId(),
                            createWebViewEvent(webView, url)));
        }

        private void emitFinishEvent(WebView webView, String url) {
            dispatchEvent(
                    webView,
                    new TopLoadingFinishEvent(
                            webView.getId(),
                            createWebViewEvent(webView, url)));
        }

        private void dispatchEvent(WebView webView, Event event) {
            ReactContext reactContext = (ReactContext) webView.getContext();
            EventDispatcher eventDispatcher =
                    reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
            eventDispatcher.dispatchEvent(event);
        }

        private WritableMap createWebViewEvent(WebView webView, String url) {
            WritableMap event = Arguments.createMap();
            event.putDouble("target", webView.getId());
            // Don't use webView.getUrl() here, the URL isn't updated to the new value yet in callbacks
            // like onPageFinished
            event.putString("url", url);
            event.putBoolean("loading", !mLastLoadFailed && webView.getProgress() != 100);
            event.putString("title", webView.getTitle());
            event.putBoolean("canGoBack", webView.canGoBack());
            event.putBoolean("canGoForward", webView.canGoForward());
            return event;
        }

        @Override
        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
            if (userName != null && password != null) {
                handler.proceed(userName, password);
            } else {
                super.onReceivedHttpAuthRequest(view, handler, host, realm);
            }
        }

        //安卓缓存机制 安卓5.0之后使用此方法
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
            if (assetsCacheEnable) {//判断是否启用预装资源
                InputStream inputStream = null;
                String fileName = "";
                try {
                    fileName = URLEncoder.encode(request.getUrl().toString(), "utf-8").toLowerCase();//大写转小写
                    inputStream = view.getContext().getAssets().open("www/" + fileName);
                } catch (IOException e) {
                    //资源文件不存在，这里不处理
                }
                if (inputStream == null) {
                    return super.shouldInterceptRequest(view, request);
                } else {
                    return new WebResourceResponse(getMimeTypeBySuffix(request.getUrl().toString()), "utf-8", inputStream);
                }
            } else {
                return super.shouldInterceptRequest(view, request);
            }
        }

        //安卓缓存机制 安卓5.0之前使用此方法
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            if (assetsCacheEnable) {//判断是否启用预装资源
                InputStream inputStream = null;
                String fileName = "";
                try {
                    fileName = URLEncoder.encode(url, "utf-8").toLowerCase();//大写转小写
                    inputStream = view.getContext().getAssets().open("www/" + fileName);
                } catch (IOException e) {
                    //资源文件不存在，这里不处理
                }
                if (inputStream == null) {
                    return super.shouldInterceptRequest(view, url);
                } else {
                    // Log.d(TAG,"使用预装资源 ："+fileName);
                    return new WebResourceResponse(getMimeTypeBySuffix(fileName), "utf-8", inputStream);
                }
            } else {
                return super.shouldInterceptRequest(view, url);
            }
        }

        public String getMimeTypeBySuffix(String url) {
            String result = "";
            if (url.endsWith("png") || url.endsWith("PNG")) {
                result = "image/png";
            } else if (url.endsWith("jpg") || url.endsWith("JPG")
                    || url.endsWith("jpeg") || url.endsWith("JPEG")) {
                result = "image/jpg";
            } else if (url.endsWith("css") || url.endsWith("css.map")) {
                result = "text/css";
            } else if (url.endsWith("js") || url.endsWith(".js.map")) {
                result = "application/javascript";
            } else {
                result = "text/plain";
            }
            return result;
        }
    }


    /**
     * Subclass of {@link WebView} that implements {@link LifecycleEventListener} interface in order
     * to call {@link WebView#destroy} on activty destroy event and also to clear the client
     */
    private class ReactWebView extends WebView implements LifecycleEventListener {
        private
        @Nullable
        String injectedJS;

        /**
         * WebView must be created with an context of the current activity
         * <p/>
         * Activity Context is required for creation of dialogs internally by WebView
         * Reactive Native needed for access to ReactNative internal system functionality
         */
        public ReactWebView(ThemedReactContext reactContext) {
            super(reactContext);
        }

        @Override
        public void onHostResume() {
            // do nothing
        }

        @Override
        public void onHostPause() {
            // do nothing
        }

        @Override
        public void onHostDestroy() {
            cleanupCallbacksAndDestroy();
        }

        public void setInjectedJavaScript(@Nullable String js) {
            injectedJS = js;
        }

        public void callInjectedJavaScript() {
            if (getSettings().getJavaScriptEnabled() &&
                    injectedJS != null &&
                    !TextUtils.isEmpty(injectedJS)) {
                loadUrl("javascript:(function() {\n" + injectedJS + ";\n})();");
            }
        }

        private void cleanupCallbacksAndDestroy() {
            setWebViewClient(null);
            destroy();
        }

    }

    public YuanXinWebViewManager() {
        mWebViewConfig = new WebViewConfig() {
            public void configWebView(WebView webView) {
            }
        };
    }

    public YuanXinWebViewManager(WebViewConfig webViewConfig) {
        mWebViewConfig = webViewConfig;
    }

    @Override
    public String getName() {
        return REACT_CLASS;
    }

    private Context context;

    @Override
    protected WebView createViewInstance(final ThemedReactContext reactContext) {
        this.context = reactContext;
        ReactWebView webView = new ReactWebView(reactContext);
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onConsoleMessage(ConsoleMessage message) {
                if (ReactBuildConfig.DEBUG) {
                    return super.onConsoleMessage(message);
                }
                return true;
            }


            @Override
            public void onGeolocationPermissionsHidePrompt() {
                super.onGeolocationPermissionsHidePrompt();
            }

            @Override
            public void onGeolocationPermissionsShowPrompt(final String origin,
                                                           final GeolocationPermissions.Callback callback) {
                AlertDialog.Builder builder = new AlertDialog.Builder(reactContext);
                builder.setMessage("请允许访问位置信息？");
                DialogInterface.OnClickListener dialogButtonOnClickListener = new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int clickedButton) {
                        if (DialogInterface.BUTTON_POSITIVE == clickedButton) {
                            callback.invoke(origin, true, true);
                        } else if (DialogInterface.BUTTON_NEGATIVE == clickedButton) {
                            callback.invoke(origin, false, false);
                        }
                    }
                };
                builder.setPositiveButton("Allow", dialogButtonOnClickListener);
                builder.setNegativeButton("Deny", dialogButtonOnClickListener);
                builder.show();
                super.onGeolocationPermissionsShowPrompt(origin, callback);
            }

        });
        reactContext.addLifecycleEventListener(webView);
        mWebViewConfig.configWebView(webView);
        webView.addJavascriptInterface(this, "WebViewBridge");
        webView.getSettings().setBuiltInZoomControls(true);
        webView.getSettings().setDomStorageEnabled(true);    //开启DOM形式存储
        webView.getSettings().setDatabaseEnabled(true);   //开启数据库形式存储
        String appCacheDir = reactContext.getApplicationContext().getDir("cache", Context.MODE_PRIVATE).getPath();   //缓存数据的存储地址
        webView.getSettings().setAppCachePath(appCacheDir);
        webView.getSettings().setAppCacheEnabled(true);  //开启缓存功能
        webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);      //缓存模式
        webView.getSettings().setAllowFileAccess(true);
        webView.getSettings().setDisplayZoomControls(false);
        webView.getSettings().setDomStorageEnabled(true);
        webView.getSettings().setGeolocationEnabled(true);
        webView.getSettings().setGeolocationDatabasePath(reactContext.getFilesDir().getPath());
        webView.getSettings().setSavePassword(false);
        webView.getSettings().setTextZoom(100);
        webView.setLayoutParams(
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT));
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
        }
        if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            WebView.setWebContentsDebuggingEnabled(true);
        }
        webView.setWebContentsDebuggingEnabled(true);
        contentWebView = webView;
        webViewList.add(contentWebView);
        contentWebView.setDownloadListener(new DownloadListener() {
            @Override
            public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
                downloadUrl=url;
                downloadBySystem(url,getMIMEType(url));
            }
        });
        return webView;
    }

    /**
     * 是否启用资源缓存  true 启用 false 不启用
     *
     * @param view
     * @param assetsCacheEnable
     */
    @ReactProp(name = "assetsCacheEnable", defaultBoolean = false)
    public void setAssetsCacheEnable(WebView view, boolean assetsCacheEnable) {
        this.assetsCacheEnable = assetsCacheEnable;
    }

    @ReactProp(name = "longPressForbidden")
    public void longPressForbidden(WebView view, boolean forbidden) {
        final boolean onLongClickEnabled = forbidden;
        view.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                return onLongClickEnabled;
            }
        });
    }

    @ReactProp(name = "javaScriptEnabled")
    public void setJavaScriptEnabled(WebView view, boolean enabled) {
        view.getSettings().setJavaScriptEnabled(enabled);
    }

    @ReactProp(name = "scalesPageToFit")
    public void setScalesPageToFit(WebView view, boolean enabled) {
        view.getSettings().setUseWideViewPort(!enabled);
    }

    @ReactProp(name = "userName")
    public void setUserName(WebView view, String userName) {
        this.userName = userName;
    }

    @ReactProp(name = "password")
    public void setPassword(WebView view, String password) {
        this.password = password;
    }

    @ReactProp(name = "domStorageEnabled")
    public void setDomStorageEnabled(WebView view, boolean enabled) {
        view.getSettings().setDomStorageEnabled(enabled);
    }

    @ReactProp(name = "userAgent")
    public void setUserAgent(WebView view, @Nullable String userAgent) {
        if (userAgent != null) {
            // TODO(8496850): Fix incorrect behavior when property is unset (uA == null)
            view.getSettings().setUserAgentString(view.getSettings().getUserAgentString()+" "+userAgent);
        }
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    @ReactProp(name = "mediaPlaybackRequiresUserAction")
    public void setMediaPlaybackRequiresUserAction(WebView view, boolean requires) {
        view.getSettings().setMediaPlaybackRequiresUserGesture(requires);
    }

    @ReactProp(name = "injectedJavaScript")
    public void setInjectedJavaScript(WebView view, @Nullable String injectedJavaScript) {
        ((ReactWebView) view).setInjectedJavaScript(injectedJavaScript);
    }

    HashMap<String, String> headerMap = new HashMap<>();

    @ReactProp(name = "source")
    public void setSource(WebView view, @Nullable ReadableMap source) {
        if (source != null) {
            Log.i(TAG,"source"+source.toString());
            if (source.hasKey("html")) {
                String html = source.getString("html");
                if (source.hasKey("baseUrl")) {
                    view.loadDataWithBaseURL(
                            source.getString("baseUrl"), html, "text/html", "UTF-8", null);
                } else {
                    view.loadDataWithBaseURL(null,html, "text/html", "UTF-8",null);
                }
                return;
            }
            if (source.hasKey("uri")) {
                String url = source.getString("uri");
                if (source.hasKey("method")) {
                    String method = source.getString("method");
                    if (method.equals(HTTP_METHOD_POST)) {
                        byte[] postData = null;
                        if (source.hasKey("body")) {
                            String body = source.getString("body");
                            try {
                                postData = body.getBytes("UTF-8");
                            } catch (UnsupportedEncodingException e) {
                                postData = body.getBytes();
                            }
                        }
                        if (postData == null) {
                            postData = new byte[0];
                        }
                        view.postUrl(url, postData);
                        return;
                    }
                }
                if (source.hasKey("headers")) {
                    ReadableMap headers = source.getMap("headers");
                    ReadableMapKeySetIterator iter = headers.keySetIterator();
                    while (iter.hasNextKey()) {
                        String key = iter.nextKey();
                        headerMap.put(key, headers.getString(key));
                    }
                }
                Log.e(getName(),"headerMap="+headerMap.toString());
                view.loadUrl(url, headerMap);
                return;
            }
        }
        view.loadUrl(BLANK_URL);
    }


    private class YuanXinWebViewChromeClient extends WebChromeClient {
        ReactContext reactContext;

        public YuanXinWebViewChromeClient(ReactContext reactContext) {
            this.reactContext = reactContext;
        }

        /**
         * Tell the client to show a file chooser.
         * <p/>
         * This is called to handle HTML forms with 'file' input type, in response to the
         * user pressing the "Select File" button.
         * To cancel the request, call <code>filePathCallback.onReceiveValue(null)</code> and
         * return true.
         *
         * @param webView           The WebView instance that is initiating the request.
         * @param filePathCallback  Invoke this callback to supply the list of paths to files to upload,
         *                          or NULL to cancel. Must only be called if the
         *                          <code>showFileChooser</code> implementations returns true.
         * @param fileChooserParams Describes the mode of file chooser to be opened, and options to be
         *                          used with it.
         * @return true if filePathCallback will be invoked, false to use default handling.
         * @see FileChooserParams
         */
        @Override
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {

            try {
                YuanXinWebViewCommon.filePathCallback = filePathCallback;
                Intent intent = new Intent();
                intent.setClass(this.reactContext, YuanXinWebViewImageActivity.class);
                this.reactContext.startActivity(intent);
            } catch (ActivityNotFoundException e) {
                return false;
            }
            return true;
        }

        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            new AlertDialog.Builder(reactContext).setTitle("Alert").setMessage(message).create().show();
            result.confirm();
            return true;
        }

        @SuppressWarnings("unused")
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            // Log.d(REACT_CLASS, "sd");

        }

        // For Android 3.0+
        @SuppressWarnings("unused")
        public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
            // Log.d(REACT_CLASS, "sd");
        }

        // For Android 4.1+
        @SuppressWarnings("unused")
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
            try {
                YuanXinWebViewCommon.uploadMsg = uploadMsg;
                Intent intent = new Intent();
                intent.setClass(this.reactContext, YuanXinWebViewImageActivity.class);
                this.reactContext.startActivity(intent);
            } catch (Exception ex) {
                // Log.d(REACT_CLASS, ex.getMessage());
            }
        }

        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
            String url = view.getUrl();
            if (url != null && !url.equals("about:blank")) {
                // Log.d(TAG,"newProgress : "+newProgress);
                WritableMap event = Arguments.createMap();
                event.putDouble("progress", newProgress);
                ReactContext reactContext = (ReactContext) view.getContext();
                reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
                        view.getId(),
                        "onProgressChanged",
                        event);
            }
        }
        private View mVideoView;
        private WebChromeClient.CustomViewCallback mCustomViewCallback;
        private Boolean isVideoFullscreen;

        private final FrameLayout.LayoutParams FULLSCREEN_LAYOUT_PARAMS = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT, Gravity.CENTER);

        @Override
        public void onShowCustomView(View view, CustomViewCallback callback) {
            if (mVideoView != null) {
                callback.onCustomViewHidden();
                return;
            }
            // Store the view and it's callback for later, so we can dispose of them
            // correctly
            mVideoView = view;
            mCustomViewCallback = callback;

            view.setBackgroundColor(Color.BLACK);
            reactContext.getCurrentActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            getRootView().addView(mVideoView, FULLSCREEN_LAYOUT_PARAMS);
            // ((View) mWebView.getRootView()).setVisibility(View.GONE);
            isVideoFullscreen = true;

            reactContext.getCurrentActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);


        }
        private ViewGroup getRootView() {
            return ((ViewGroup) reactContext.getCurrentActivity().findViewById(android.R.id.content));
        }
        @Override
        public void onHideCustomView() {
            if (mVideoView == null) {
                return;
            }
            reactContext.getCurrentActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            ((View) contentWebView.getRootView()).setVisibility(View.VISIBLE);
            mVideoView.setVisibility(View.GONE);

            // Remove the custom view from its container.
            getRootView().removeView(mVideoView);
            mVideoView = null;
            mCustomViewCallback.onCustomViewHidden();
            isVideoFullscreen = false;
            reactContext.getCurrentActivity().getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);


//            Window window = reactContext.getCurrentActivity().getWindow();
//            //取消状态栏透明
//            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//            //添加Flag把状态栏设为可绘制模式
//            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//            //设置状态栏颜色
//            window.setStatusBarColor(Color.BLACK);
//            //设置系统状态栏处于可见状态
//            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
//            //让view不根据系统窗口来调整自己的布局
//            ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
//            View mChildView = mContentView.getChildAt(0);
//            if (mChildView != null) {
//                ViewCompat.setFitsSystemWindows(mChildView, false);
//                ViewCompat.requestApplyInsets(mChildView);
//            }
        }

    }

    @Override
    protected void addEventEmitters(ThemedReactContext reactContext, WebView view) {
        // Do not register default touch emitter and let WebView implementation handle touches
        view.setWebChromeClient(new YuanXinWebViewChromeClient(reactContext));
        view.setWebViewClient(new ReactWebViewClient());
    }

    @Override
    public
    @Nullable
    Map<String, Integer> getCommandsMap() {
        return  MapBuilder.<String,Integer>builder()
                .put("goBack", COMMAND_GO_BACK)
                .put("goForward", COMMAND_GO_FORWARD)
                .put("reload", COMMAND_RELOAD)
                .put("stopLoading", COMMAND_STOP_LOADING)
                .put("sendToBridge", COMMAND_SEND_TO_BRIDGE)
                .put("sendDataToBridge", COMMAND_SEND_DATA_BRIDGE)
                .put("evaluateScript", COMMAND_EVALUATE_SCRIPT)
                .build();
    }

    @Override
    public
    @Nullable
    Map getExportedCustomDirectEventTypeConstants() {
        return
                MapBuilder.of(
                        "onBridgeMessage", MapBuilder.of("registrationName", "onBridgeMessage"),
                        "onHeightChange", MapBuilder.of("registrationName", "onHeightChange"),
                        "onProgressChanged", MapBuilder.of("registrationName", "onProgressChanged")
                );
    }

    public void onHeightChange(ReactWebView view, float height) {
        // Log.d(REACT_CLASS, "height===>" + height);
        WritableMap event = Arguments.createMap();
        event.putDouble("height", height);
        ReactContext reactContext = (ReactContext) view.getContext();
        reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
                view.getId(),
                "onHeightChange",
                event);
    }

    @JavascriptInterface
    public void send(String message) {
        // Log.d(REACT_CLASS, "send===>" + message);
        WritableMap event = Arguments.createMap();
        event.putString("message", message);
        WebView webView = null;
        try {
            webView = webViewList.get(webViewList.size() - 1);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if (webView != null) {
            ReactContext reactContext = (ReactContext) webView.getContext();
            reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
                    webView.getId(),
                    "onBridgeMessage",
                    event);
        }
    }

    private WebView getContentView() {
        return this.contentWebView;
    }

    @Override
    public void receiveCommand(WebView root, int commandId, @Nullable ReadableArray args) {
        switch (commandId) {
            case COMMAND_GO_BACK:
                root.goBack();
                break;
            case COMMAND_GO_FORWARD:
                root.goForward();
                break;
            case COMMAND_RELOAD:
                root.reload();
                break;
            case COMMAND_STOP_LOADING:
                root.stopLoading();
                break;
            case COMMAND_SEND_TO_BRIDGE:
                //因为webview会把字符串中的双斜杠变为单斜杠，所以这里将双斜杠加倍，保证数据传递正确
                String json = args.getString(0).replace("\\", "\\\\");
                //Log.i(getName(), "===>" + json);
                root.loadUrl("javascript:WebViewBridge.onMessage('" + json + "')");
                break;
            case COMMAND_SEND_DATA_BRIDGE:
                break;
            case COMMAND_EVALUATE_SCRIPT:
                root.loadUrl("javascript:" + args.getString(0) + "");
                break;

        }
    }


    @Override
    public void onDropViewInstance(WebView webView) {
        super.onDropViewInstance(webView);
        ((ThemedReactContext) webView.getContext()).removeLifecycleEventListener((ReactWebView) webView);
        ((ReactWebView) webView).cleanupCallbacksAndDestroy();
        if (webViewList.contains(webView))
            webViewList.remove(webView);
    }

    private String getMIMEType(String url) {
        String type = null;
        String extension = MimeTypeMap.getFileExtensionFromUrl(url);
        Log.i(TAG, extension);
        if (extension != null) {
            type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
        }
        return type;
    }

    /**
     * 使用系统下载方法
     * @param url
     * @param mimeType
     */
    private void downloadBySystem(String url, String mimeType) {
        // 指定下载地址
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        // 允许媒体扫描，根据下载的文件类型被加入相册、音乐等媒体库
        request.allowScanningByMediaScanner();
        // 设置通知的显示类型，下载进行时和完成后显示通知
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        // 允许在计费流量下下载
        request.setAllowedOverMetered(true);
        // 允许该记录在下载管理界面可见
        request.setVisibleInDownloadsUi(true);
        // 允许漫游时下载
        request.setAllowedOverRoaming(true);
        // 允许下载的网路类型
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
        // 设置下载文件保存的路径和文件名
        String fileName  = URLUtil.guessFileName(url,null , mimeType);
        Log.i(TAG,"fileName="+ fileName);
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
        final DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
        // 添加一个下载任务
        long downloadId = downloadManager.enqueue(request);
        Log.i(TAG,"downloadId="+ downloadId);
    }
}
